#include "xict_driver/task/periodic_task.h"
#include "xict_common/log/log.h"

namespace xict_driver {
    namespace task {
        PeriodicTask::PeriodicTask(PeriodicTaskManager* _task_manager,
                                   float _period, std::string _name)
            : period_(_period), name_(_name) {
            _task_manager->AddTask(this);
        }

        void PeriodicTask::Start() {
            if (running_flag_) {
                AWARN_F("[PeriodicTask] Tried to start {} but it was already "
                        "running!\n",
                        name_.c_str());
                return;
            }

            Init();
            running_flag_ = true;
            thread_       = std::thread(&PeriodicTask::LoopFunction, this);
        }

        void PeriodicTask::Stop() {
            if (!running_flag_) {
                AWARN_F(
                    "[PeriodicTask] Tried to stop {} but it wasn't running!\n",
                    name_.c_str());
                return;
            }
            running_flag_ = false;
            ADEBUG_F("[PeriodicTask] Waiting for {} to stop...\n",
                     name_.c_str());
            thread_.join();
            ADEBUG_F("[PeriodicTask] Done!\n");
            Cleanup();
        }

        void PeriodicTask::PrintStatus() {
            if (!running_flag_)
                return;
            printf("|%-20s|%6.4f|%6.4f|%6.4f|%6.4f|%6.4f\n", name_.c_str(),
                   last_runtime_, max_runtime_, period_, last_period_time_,
                   max_period_);
        }

        void PeriodicTask::ClearMax() {
            max_period_  = 0;
            max_runtime_ = 0;
        }

        bool PeriodicTask::IsSlow() {
            return max_period_ > period_ * 1.3f || max_runtime_ > period_;
        }

        bool PeriodicTask::IsAbnormal() {
            return abnormal_flag_;
        }

        void PeriodicTask::RegExceptionCallback(
            const std::function<void(const xict_driver::utils::ErrorInfo&)>&
                cb_excep) {
            cb_exception_ = cb_excep;
        }

        void PeriodicTask::LoopFunction() {
            int seconds     = (int)period_;
            int nanoseconds = (int)(1e9 * std::fmod(period_, 1.f));
            //时钟对时间的测量始于系统启动
            auto timer_fd = timerfd_create(CLOCK_MONOTONIC, 0);
            itimerspec timer_spec;
            timer_spec.it_interval.tv_sec  = seconds;
            timer_spec.it_value.tv_sec     = seconds;
            timer_spec.it_value.tv_nsec    = nanoseconds;
            timer_spec.it_interval.tv_nsec = nanoseconds;
            timerfd_settime(timer_fd, 0, &timer_spec, nullptr);

            xict_common::utils::Timer t;

            unsigned long long missed = 0;

            ADEBUG_F("[PeriodicTask] Start {} ({} s, {} ns)\n", name_.c_str(),
                     seconds, nanoseconds);
            while (running_flag_) {
                last_period_time_ = (float)t.GetSeconds();
                t.Start();
                Run();
                last_runtime_ = (float)t.GetSeconds();

                int m = read(timer_fd, &missed, sizeof(missed));
                (void)m;

                max_period_  = std::max(max_period_, last_period_time_);
                max_runtime_ = std::max(max_runtime_, last_runtime_);
            }
            ADEBUG_F("[PeriodicTask] {} has stopped!\n", name_.c_str());
        }

        PeriodicTaskManager::~PeriodicTaskManager() { }

        void
        PeriodicTaskManager::AddTask(xict_driver::task::PeriodicTask* task) {
            tasks_.push_back(task);
        }

        void PeriodicTaskManager::PrintStatus() {
            printf("\n----------------------------TASKS------------------------"
                   "----"
                   "\n");
            printf("|%-20s|%-6s|%-6s|%-6s|%-6s|%-6s\n", "name", "rt", "rt-max",
                   "T-des", "T-act", "T-max");
            printf("-----------------------------------------------------------"
                   "\n");
            for (auto& task : tasks_) {
                task->PrintStatus();
                task->ClearMax();
            }
            printf(
                "-------------------------------------------------------------"
                "\n\n");
        }

        void PeriodicTaskManager::PrintStatusOfSlowTasks() {
            for (auto& task : tasks_) {
                if (task->IsSlow()) {
                    task->PrintStatus();
                    task->ClearMax();
                }
            }
        }

        void PeriodicTaskManager::StartAll() {
            for (auto& task : tasks_) {
                task->Start();
            }
        }

        void PeriodicTaskManager::StopAll() {
            for (auto& task : tasks_) {
                task->Stop();
            }
        }

        size_t PeriodicTaskManager::GetTaskNum() {
            return tasks_.size();
        }

        void PeriodicTaskManager::MonitorTasks() {
            for (auto& task : tasks_) {
                // 监控任务每次循环的时间
                if (task->IsSlow()) {
                    task->PrintStatus();
                    task->ClearMax();
                }

                // 监控任务是否异常，若异常重启任务
                if (task->IsAbnormal()) {
                    ADEBUG_F("[PeriodicTaskManager] Task < {} > is anbormal. "
                             "Restart "
                             "the task "
                             "automatically \n",
                             task->GetName().c_str());
                    task->Stop();
                    task->Start();
                }
            }
        }
    }   // namespace task
}   // namespace xict_driver